package com.jooink.experiments.elementalgetusermedia.client;

import java.util.ArrayList;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.jooink.experiments.elementalgetusermedia.client.ElementalUtils.UserMediaCallback;

import elemental.client.Browser;
import elemental.events.Event;
import elemental.events.EventListener;
import elemental.html.CanvasElement;
import elemental.html.CanvasRenderingContext2D;
import elemental.html.VideoElement;

/**
 * trivial sample of video/canvas & getUSerMedia
 */
public class ElementalGetUserMediaDemo implements EntryPoint {




	//caching a canvas
	private CanvasElement canvas = Browser.getDocument().createCanvasElement();

	private ImagesStrip images ;

	private static final int tiles_w = 160;
	private static final int tiles_h = 120;



	@Override
	public void onModuleLoad() {



		final UserMediaHolder userMediaHolder = new UserMediaHolder();




		int h = Window.getClientHeight();
		int w = Window.getClientWidth();

		int Nx = w/160;
		int Ny = h/120;

		images = new ImagesStrip(Nx*Ny, tiles_w + "px", tiles_h + "px");



		RootLayoutPanel.get().add(images);


		Button cam = new Button("Capture My Cam");
		cam.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if(!userMediaHolder.getUserMedia(userMediaCallback)) 
					Window.alert("FAIL: your browser \""+ Window.Navigator.getUserAgent()+"\" does not support WebRTC's getUserMedia :(");
			};
		});

		PopupPanel pp = new PopupPanel(false, true);
		pp.add(cam);
		pp.center();
		pp.show();




	}




	private  String makePicture(VideoElement videoElement, CanvasElement canvasElement) {
		canvasElement.setWidth( videoElement.getVideoWidth());
		canvasElement.setHeight( videoElement.getVideoHeight());
		elemental.html.CanvasRenderingContext2D ctx = (CanvasRenderingContext2D) canvasElement.getContext("2d");
		ctx.drawImage(videoElement, 0, 0);
		return canvasElement.toDataURL("image/png");
	}



	private  final UserMediaCallback userMediaCallback = new UserMediaCallback()  {

		public void onSuccess(String s) {	

			final PopupPanel popupPanel = new PopupPanel(false,true);

			final ElementalVideoWidget video = new ElementalVideoWidget();

			video.getVideoElement().setSrc(s);
			video.getVideoElement().play();


			popupPanel.setWidget(new HTML("Waiting for video to become available"));
			popupPanel.center();
			popupPanel.show();


			//finalize the ui when the video is available
			video.getVideoElement().addEventListener("loadedmetadata", new EventListener() {
				@Override
				public void handleEvent(Event evt) {
					int w = video.getVideoElement().getVideoWidth();
					int h = video.getVideoElement().getVideoHeight();

					video.setSize(w+"px", h+"px");

					final VerticalPanel vp = new VerticalPanel();
					vp.add(video);

					final HorizontalPanel hp = new HorizontalPanel();
					Anchor click = new Anchor("make a picture");
					click.addClickHandler( new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {
							String data = makePicture(video.getVideoElement(), canvas);
							
							
							
							Anchor done = new Anchor("done");
							done.getElement().getStyle().setColor("red");
							done.addClickHandler(new ClickHandler() {
								@Override
								public void onClick(ClickEvent event) {
									popupPanel.hide();
								}
							});
							
							vp.clear();
							vp.add(new Image(data));							
							vp.add(hp);
							hp.clear();
							hp.add(done);
							hp.setCellHorizontalAlignment(done, HasHorizontalAlignment.ALIGN_CENTER);
						}
					});

					Anchor close = new Anchor("close");
					close.addClickHandler(new ClickHandler() {	
						@Override
						public void onClick(ClickEvent event) {
							popupPanel.hide();
						}
					});

					Anchor timely_circular = new Anchor("stream (circular)");
					timely_circular.addClickHandler( new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {

							final Timer timer = new Timer() {
								@Override
								public void run() {
									String data = makePicture(video.getVideoElement(),canvas);
									images.push_circular(data);
								}
							};

							Anchor stop = new Anchor("stop");
							stop.getElement().getStyle().setColor("red");
							stop.addClickHandler(new ClickHandler() {

								@Override
								public void onClick(ClickEvent event) {
									timer.cancel();
									popupPanel.hide();
								}
							});

							hp.clear();
							hp.add(stop);
							hp.setCellHorizontalAlignment(stop, HasHorizontalAlignment.ALIGN_CENTER);
							video.getVideoElement().setWidth(tiles_w);
							video.getVideoElement().setHeight(tiles_h);
							video.setSize(tiles_w + "px", tiles_h + "px");
							popupPanel.center();
							String data = makePicture(video.getVideoElement(),canvas);
							images.push_circular(data);
							timer.scheduleRepeating(250);
						}
					});

					Anchor timely_moving = new Anchor("stream (moving)");
					timely_moving.addClickHandler( new ClickHandler() {
						@Override
						public void onClick(ClickEvent event) {

							final Timer timer = new Timer() {
								@Override
								public void run() {
									String data = makePicture(video.getVideoElement(),canvas);
									images.push_shift(data);
								}
							};

							Anchor stop = new Anchor("stop");
							stop.getElement().getStyle().setColor("red");
							stop.addClickHandler(new ClickHandler() {

								@Override
								public void onClick(ClickEvent event) {
									timer.cancel();
									popupPanel.hide();
								}
							});

							hp.clear();
							hp.add(stop);
							hp.setCellHorizontalAlignment(stop, HasHorizontalAlignment.ALIGN_CENTER);
							video.getVideoElement().setWidth(tiles_w);
							video.getVideoElement().setHeight(tiles_h);
							video.setSize(tiles_w + "px", tiles_h + "px");
							popupPanel.center();
							String data = makePicture(video.getVideoElement(),canvas);
							images.push_shift(data);
							timer.scheduleRepeating(250);
						}
					});


					hp.setWidth("100%");

					hp.add(click);
					hp.setCellHorizontalAlignment(click, HasHorizontalAlignment.ALIGN_LEFT);
					hp.setCellWidth(click, "25%");

					hp.add(timely_circular);
					hp.setCellHorizontalAlignment(timely_circular, HasHorizontalAlignment.ALIGN_CENTER);
					hp.setCellWidth(timely_circular, "25%");

					hp.add(timely_moving);
					hp.setCellHorizontalAlignment(timely_moving, HasHorizontalAlignment.ALIGN_CENTER);
					hp.setCellWidth(timely_moving, "25%");

					hp.add(close);
					hp.setCellHorizontalAlignment(close, HasHorizontalAlignment.ALIGN_RIGHT);
					hp.setCellWidth(close, "25%");

					vp.add(hp);

					popupPanel.setWidget(vp);
					popupPanel.center();					
				}
			});



		}


		public void onFail() {
			Window.alert("FAIL: please let me access your camera");
		}
	};



	public class ImagesStrip implements IsWidget {
		private FlowPanel panel = new FlowPanel();
		private ArrayList<Image> images = new ArrayList<Image>();
		@Override
		public Widget asWidget() {
			return panel;
		}

		private int current = 0;
		private int len;
		private String width;
		private String height;
		public ImagesStrip(int len, String w, String h) {
			this.len = len;
			this.width = w;
			this.height = h;
		}


		public void push_circular(String url) {
			int pos = current%len;

			if(images.size() <= pos) {
				Image img = new Image();
				img.setSize(width, height);
				panel.add(img);
				images.add(img);
			}
			images.get(pos).setUrl(url);
			current++;
		}

		public void push_shift(String url) {

			int pos = current%len;

			if(images.size() <= pos) {
				Image img = new Image();
				img.setSize(width, height);
				panel.add(img);
				images.add(img);
			} 
			if(current > len) {
				Image img = images.get(pos);
				panel.remove(img);
				panel.add(img);
			}
			images.get(pos).setUrl(url);


			current++;
		}


	}


}
